using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

using Acms.SqlDal;

namespace Acms.Bll
{
    public class Post : BaseItem
    {
        protected Post() : base() { }

        protected Post(Hashtable table) : base(table) { }

        protected Post(Hashtable table, ICollection collection) : base(table, collection) { }

        public static Post CreateInstance()
        {
            return new Post();
        }

        protected override Base CreateDal()
        {
            return new PostDal();
        }

        private static Post Get(Hashtable table)
        {
            if (table == null)
            {
                return null;
            }
            else
            {
                return new Post(table);
            }

        }

        private static List<Post> Get(Hashtable[] tables)
        {
            if (tables == null)
            {
                return null;
            }
            else
            {
                List<Post> tmp = new List<Post>();
                foreach (Hashtable table in tables)
                {
                    tmp.Add(new Post(table, tmp));
                }
                return tmp;
            }
        }

        public static Post GetTopLevelBySiteId(int siteId, DateTime? siteVersion)
        {
            PostDal dal = new PostDal();
            return Get(dal.GetTopLevelBySiteId(siteId, siteVersion));

        }

        public static List<Post> GetAllBySiteId(int siteId, DateTime? siteVersion)
        {
            PostDal dal = new PostDal();
            return Get(dal.GetAllBySiteId(siteId, siteVersion));
        }


        public static List<Post> GetAllBySiteIdMenuIdAndParentPath(int siteId, int menuId, string parentPath, DateTime? siteVersion)
        {
            PostDal dal = new PostDal();
            return Get(dal.GetAllBySiteIdMenuIdAndParentPath(siteId, menuId, parentPath, siteVersion));
        }

        public static List<Post> GetAllBySiteIdAndParentPath(int siteId, string parentPath, DateTime? siteVersion)
        {
            PostDal dal = new PostDal();
            return Get(dal.GetAllBySiteIdAndParentPath(siteId, parentPath, siteVersion)); 
        }

        public static List<Post> GetAllByMenuIdAndParentGuid(int siteId, int menuId, Guid parentGuid, DateTime? siteVersion)
        {
            PostDal dal = new PostDal();
            return Get(dal.GetAllByMenuIdAndParentGuid(siteId, menuId, parentGuid, siteVersion));
        }

        public static List<Post> GetAllByMenuId(int siteId, int menuId, DateTime? siteVersion)
        {
            PostDal dal = new PostDal();
            return Get(dal.GetAllByMenuId(siteId, menuId, siteVersion));
        }

        
        public static List<Post> GetAllByParentGuid(int siteId, Guid parentGuid, DateTime? siteVersion)
        {
            PostDal dal = new PostDal();
            return Get(dal.GetAllByParentGuid(siteId, parentGuid, siteVersion));
        }

        public static Post GetBySiteUrlAndPath(string siteUrl, string postPath, DateTime? siteVersion)
        {
            PostDal dal = new PostDal();
            return Get(dal.GetBySiteUrlAndPath(siteUrl, postPath, siteVersion));
        }

        public static Post GetBySiteIdAndPath(int siteId, string path, DateTime? siteVersion)
        {
            PostDal dal = new PostDal();
            return Get(dal.GetBySiteIdAndPath(siteId, path, siteVersion));
        }

        public static List<Post> GetAllByParentGuidAndTopicId(int siteId, Guid parentGuid, int topicId, DateTime? siteVersion, bool includeChildren, int startIndex, int pageSize, ref int totalRecords)
        {
            PostDal dal = new PostDal();
            return Get(dal.GetAllByParentGuidAndTopicId(siteId, parentGuid, topicId, siteVersion, includeChildren, startIndex, pageSize, ref totalRecords));
        }

        public static List<Post> GetAllWhereRequiresPublishing(int siteId)
        {
            PostDal dal = new PostDal();
            return Get(dal.GetAllWhereRequiresPublishing(siteId));
        }

        public static Post GetById(int siteId, int id, DateTime? siteVersion)
        {
            PostDal dal = new PostDal();
            return Get(dal.GetById(siteId, id, siteVersion));
        }

        internal static Post GetById(int id)
        {
            PostDal dal = new PostDal();
            return Get(dal.GetById(id));
        }

        public static Post GetByPostGuid(int siteId, Guid postGuid, DateTime? siteVersion)
        {
            PostDal dal = new PostDal();
            return Get(dal.GetByPostGuid(siteId, postGuid, siteVersion));
        }

        public static List<Post> GetAllByTopicId(int siteId, int topicId, DateTime? siteVersion)
        {
            PostDal dal = new PostDal();
            return Get(dal.GetAllByTopicId(siteId, topicId, siteVersion));
        }

        public static List<Post> GetAllByTopicIdAndParentPath(int siteId, int topicId, string parentPath, DateTime? siteVersion)
        {
            PostDal dal = new PostDal();
            return Get(dal.GetAllByTopicIdAndParentPath(siteId, topicId, parentPath, siteVersion));
        }

        public static List<Post> GetAllByTopicIdsAndParentPath(int siteId, int[] topicIds, string parentPath, DateTime? siteVersion)
        {
            PostDal dal = new PostDal();
            return Get(dal.GetAllByTopicIdsAndParentPath(siteId, topicIds, parentPath, siteVersion));
        }

        public static List<Post> GetAllByTopicGroupIdAndParentPath(int siteId, int topicGroupId, string parentPath, DateTime? siteVersion)
        {
            PostDal dal = new PostDal();
            return Get(dal.GetAllByTopicGroupIdAndParentPath(siteId, topicGroupId, parentPath, siteVersion));
        }

        public static List<Post> GetAllByPostGuid(Guid postGuid)
        {
            PostDal dal = new PostDal();
            return Get(dal.GetAllByPostGuid(postGuid));
        }

        public static List<Post> GetCurrentVersions(int siteId, Guid postGuid)
        {
            PostDal dal = new PostDal();
            return Get(dal.GetCurrentVersions(siteId, postGuid));
        }

        public static List<Post> GetCurrentVersionsByPostId(int siteId, int postId)
        {
            PostDal dal = new PostDal();
            return Get(dal.GetCurrentVersionsByPostId(siteId, postId));
        }


        protected override void Load(Hashtable table)
        {
            _Id = (int)table[PostDal.Fields.Id];
            _SiteId = (int)table[PostDal.Fields.SiteId];
            _SiteName = (string)table[PostDal.Fields.SiteName];
            _PostGuid = (Guid)table[PostDal.Fields.PostGuid];
            _ParentGuid = (Guid?)table[PostDal.Fields.ParentGuid];
            _ParentPath = (string)table[PostDal.Fields.ParentPath];
            _Name = (string)table[PostDal.Fields.Name];
            _DisplayName = (string)table[PostDal.Fields.DisplayName];
            _TemplateId = (int)table[PostDal.Fields.TemplateId];
            _TemplateName = (string)table[PostDal.Fields.TemplateName];
            _NodeType = (Template.NodeTypes)table[PostDal.Fields.NodeType];
            _ThumbnailId = (int?)table[PostDal.Fields.ThumbnailId];
            _Summary = (string)table[PostDal.Fields.Summary];
            _Sequence = (int)table[PostDal.Fields.Sequence];
            _CreatedDateTime = (DateTime)table[PostDal.Fields.CreatedDateTime];
            _PublishFrom = (DateTime?)table[PostDal.Fields.PublishFrom];
            _PublishTo = (DateTime?)table[PostDal.Fields.PublishTo];
            _RequiresPublishing = (bool)table[PostDal.Fields.RequiresPublishing];
            _ReadyToPublish = (bool)table[PostDal.Fields.ReadyToPublish];
            _Notes = (string)table[PostDal.Fields.Notes];
            SiteVersion = (DateTime?)table[PostDal.Fields.SiteVersion];
            _DeveloperLocked = (bool)table[PostDal.Fields.DeveloperLocked];
            TitleSummary = (string)table[PostDal.Fields.TitleSummary];
            MetaKeywords = (string)table[PostDal.Fields.MetaKeywords];
        }

        private int _Id;
        public int Id
        {
            get { return _Id; }
        }

        private int _SiteId;
        public int SiteId
        {
            get { return _SiteId; }
            set 
            {
                LogChange(_SiteId, value, Change.ChangeTypes.Post, "Site Id", Id);
                _SiteId = value; 
            }
        }

        private Guid _PostGuid;
        public Guid PostGuid
        {
            get { return _PostGuid; }
        }

        private string _SiteName;
        public string SiteName
        {
            get { return _SiteName; }
        }

        private Guid? _ParentGuid;
        public Guid? ParentGuid 
        {
            get
            {
                return _ParentGuid;
            }
            set
            {
                LogChange(_ParentGuid, value, Change.ChangeTypes.Post, "Parent Guid", Id);
                _ParentGuid = value;
            }
        }

        private Post _Parent;
        public Post Parent
        {
            get 
            {
                if (_Parent == null && ParentGuid.HasValue && ParentGuid.Value != Guid.Empty)
                {
                    _Parent = Post.GetByPostGuid(SiteId, ParentGuid.Value, SiteVersion);
                }
                return _Parent;
            }
        }

        private string _Name;
        public string Name
        {
            get { return _Name; }
            set 
            {
                LogChange(_Name, value, Change.ChangeTypes.Post, "Name", Id);
                _Name = value; 
            }
        }

        private string _DisplayName;
        public string DisplayName
        {
            get { return _DisplayName; }
            set 
            {
                LogChange(_DisplayName, value, Change.ChangeTypes.Post, "Display Name", Id);
                _DisplayName = value; 
            }
        }

        private string _ParentPath;
        public string ParentPath { get { return _ParentPath; } }

        public string Path
        {
            get { return string.Concat(ParentPath, Name); }
        }

        public string ResolvePath(string path)
        {
            StringBuilder url = new StringBuilder();
            string baseUrl = path;
            string baseQS = null;
            if (path.Contains("?"))
            {
                baseUrl = path.Substring(0, path.IndexOf("?"));
                baseQS = path.Substring(path.IndexOf("?") + 1);
            }

            if(baseUrl == ".")
            {
                url.Append(this.Path);
            }
            else if (baseUrl.StartsWith("~/"))
            {
                url.Append(baseUrl);
            }
            else if(baseUrl.StartsWith("../"))
            {
                var itemsUp = 0;
                while (baseUrl.StartsWith("../"))
                {
                    itemsUp++;
                    baseUrl = baseUrl.Substring(3);
                }
                var parents = this.Path.Split('/');
                for (int i = 0; i < parents.Length - itemsUp; i++)
                {
                    url.Append(parents[i]);
                    url.Append("/");
                }
                url.Append(baseUrl);
            }
            else
            {
                url.Append(this.Path);
                if(string.IsNullOrEmpty(baseUrl) && !baseUrl.StartsWith("/"))
                    url.Append("/");
                url.Append(baseUrl);
            }
            if (url.ToString().Equals("~/"))
            {
                url.Append("default");
            }
            else if (url.ToString().EndsWith("/"))
            {
                url.Remove(url.Length - 1, 1);
            }
            url.Append(".aspx");
            string qs = null;
            if (SiteVersion == null)
            {
                qs = "AcmsSV=Pending";
            }
            else if (SiteVersion.Value > DateTime.Now)
            {
                qs = string.Concat("AcmsSV=", System.Web.HttpUtility.UrlEncode(SiteVersion.Value.ToString("yyyy/MM/dd HH:mm")));
            }

            if (qs != null)
            {
                url.Append("?");
                url.Append(qs);
            }

            if (!string.IsNullOrEmpty(baseQS))
            {
                if (url.ToString().Contains("?"))
                {
                    url.Append("&");
                }
                else
                {
                    url.Append("?");
                }
                url.Append(baseQS);
            }


            return url.ToString();
        }

        public string Url
        {
            get 
            {
                StringBuilder url = new StringBuilder();
                if (this.Id > 0 && this.Path != "~")
                {
                    url.AppendFormat("{0}{1}.aspx", ParentPath, this.Name);
                }
                else if (this.Id > 0 && this.Path == "~")
                {
                    url.Append("~/default.aspx");
                }
                else
                {
                    return null;
                }

                string qs = null;
                if (SiteVersion == null)
                {
                    qs = "AcmsSV=Pending";
                }
                else if (SiteVersion.Value > DateTime.Now || (this.PublishTo != null && this.PublishTo.Value <= DateTime.Now))
                {
                    qs = string.Concat("AcmsSV=", System.Web.HttpUtility.UrlEncode(SiteVersion.Value.ToString("yyyy/MM/dd HH:mm")));
                }
                if (qs != null)
                {
                    url.Append("?");
                    url.Append(qs);
                }
                return url.ToString();
            }
        }

        public string GetUrl(string templateName)
        {
            string tmp = this.Url;
            string spacer = "?";
            if(tmp.Contains("?"))
                spacer = "&";
            return string.Concat(tmp, spacer, "AcmsTF=", templateName); 
        }


        public string ParentUrl
        {
            get
            {
                if (ParentGuid.HasValue && ParentPath != null)
                {
                    StringBuilder url = new StringBuilder();
                    //remove final / from parent path
                    if (this.Id > 0 && ParentPath == "~/")
                    {
                        url.AppendFormat("{0}default.aspx", ParentPath);
                    }
                    else if (this.Id > 0 && this.Path != "~")
                    {
                        url.AppendFormat("{0}.aspx", ParentPath.Substring(0, ParentPath.Length - 1));
                    }
                    else
                    {
                        return null;
                    }

                    string qs = null;
                    if (SiteVersion == null)
                    {
                        qs = "AcmsSV=Pending";
                    }
                    else if (SiteVersion.Value > DateTime.Now)
                    {
                        qs = string.Concat("AcmsSV=", System.Web.HttpUtility.UrlEncode(SiteVersion.Value.ToString("yyyy/MM/dd HH:mm")));
                    }
                    if (qs != null)
                    {
                        url.Append("?");
                        url.Append(qs);
                    }
                    return url.ToString();
                }
                else
                {
                    return null;
                }
            }
        }


        private int? _ThumbnailId;
        public int? ThumbnailId
        {
            get { return _ThumbnailId; }
            set 
            {
                LogChange(_ThumbnailId, value, Change.ChangeTypes.Post, "Thumbnail Id", Id);
                _ThumbnailId = value; 
            }
        }

        private int _TemplateId;
        public int TemplateId
        {
            get { return _TemplateId; }
            set 
            {
                if (_TemplateId != value)
                {
                    LogChange(_TemplateId, value, Change.ChangeTypes.Post, "Template", Id);
                    _TemplateId = value; 
                    _Template = null;
                }
            }
        }

        private Template _Template;
        public Template Template 
        {
            get
            {
                if (_Template == null && TemplateId > 0)
                {
                    _Template = Bll.Template.GetById(TemplateId);
                }
                return _Template;
            }
        }

        private string _TemplateName;
        public string TemplateName { get { return _TemplateName; } }

        private Template.NodeTypes _NodeType;
        public Template.NodeTypes NodeType { get { return _NodeType; } }

        private string _Summary;
        public string Summary
        {
            get { return _Summary; }
            set 
            {
                LogChange(_Summary, value, Change.ChangeTypes.Post, "Summary", Id);
                _Summary = value;
            }
        }

        private int _Sequence;
        public int Sequence
        {
            get { return _Sequence; }
            set 
            {
                LogChange(_Sequence, value, Change.ChangeTypes.Post, "Sequence", Id);
                _Sequence = value; 
            }
        }

        private DateTime _CreatedDateTime;
        public DateTime CreatedDateTime { get { return _CreatedDateTime; } }
        
        private DateTime? _PublishFrom;
        public DateTime? PublishFrom 
        {
            get { return _PublishFrom; }
            set
            {
                LogChange(_PublishFrom, value, Change.ChangeTypes.Post, "Publish From", Id); 
                _PublishFrom = value;
            }
        }

        private DateTime? _PublishTo;
        public DateTime? PublishTo
        {
            get { return _PublishTo; }
            set
            {
                LogChange(_PublishTo, value, Change.ChangeTypes.Post, "Publish To", Id);
                _PublishTo = value;
            }
        }

        private bool _RequiresPublishing;
        public bool RequiresPublishing
        {
            get { return _RequiresPublishing; }
            set
            {
                LogChange(_RequiresPublishing, value, Change.ChangeTypes.Post, "Requires Publishing", Id);
                _RequiresPublishing = value;
            }
        }
        
        private bool _ReadyToPublish;
        public bool ReadyToPublish 
        {
            get { return _ReadyToPublish; }
            set
            {
                LogChange(_ReadyToPublish, value, Change.ChangeTypes.Post, "Ready To Publish", Id);
                _ReadyToPublish = value;
            }
        }

        private string _Notes;
        public string Notes
        {
            get { return _Notes; }
            set
            {
                LogChange(_Notes, value, Change.ChangeTypes.Post, "Notes", Id);
                _Notes = value;
            }
        }

        //private DateTime? _SiteVersion;
        public DateTime? SiteVersion { get; private set; }

        private bool _DeveloperLocked;
        public bool DeveloperLocked 
        { 
            get{return _DeveloperLocked;}
            set
            {
                LogChange(_DeveloperLocked, value, Change.ChangeTypes.Post, "Developer Locked", Id);
                _DeveloperLocked = value;
            }
        }

        public new void Update()
        {
            if (IsNewRecord)
            {
                this.SiteVersion = this.PublishFrom;
            }
            Update(true);
        }

        internal void Update(bool saveDefaultMenus)
        {
            bool saveMenus = IsNewRecord;
            if (!saveDefaultMenus)
                saveMenus = false;

            bool commitTran = false;

            if (saveMenus && this.TransactionKey == Guid.Empty)
            {
                commitTran = true;
                base.BeginTransaction();
            }

            base.Update();

            if (saveMenus)
            {
                List<Menu> menus = Menu.GetAllBySiteId(SiteId);
                foreach (Acms.Bll.Menu m in menus)
                {
                    Acms.Bll.PostMenu pm = Acms.Bll.PostMenu.CreateInstance(Id, m.Id, m.DefaultForAllPosts);
                    pm.UseTransaction(base.TransactionKey);
                    pm.Update();
                }
            }

            if (commitTran)
            {
                base.CommitTransaction();
            }
        }

        protected override object SaveChanges(ref object concurencyId, Base dal)
        {
            if (IsNewRecord)
            {
                this._CreatedDateTime = DateTime.Now;
                if (PostGuid == null || PostGuid == Guid.Empty)
                {
                    _PostGuid = Guid.NewGuid();
                }
            }
            int nodeTypeOut = (int)NodeType;
            ((PostDal)dal).Update(ref _Id, _SiteId, ref _SiteName, _PostGuid, _ParentGuid, ref _ParentPath, _Name, _DisplayName, _TemplateId, ref _TemplateName, ref nodeTypeOut, _ThumbnailId, _Summary, ref _Sequence, _CreatedDateTime, _PublishFrom, _PublishTo, _RequiresPublishing, _ReadyToPublish, _Notes, _DeveloperLocked, TitleSummary, MetaKeywords, ref concurencyId);
            _NodeType = (Template.NodeTypes)nodeTypeOut;
            return _Id;
        }

        public new void Delete()
        {
            base.Delete();
        }

        protected override void DeleteRecord(object concurencyId, Base dal)
        {
            bool commit = false;
            if (this.TransactionKey == null || this.TransactionKey == Guid.Empty)
            {
                BeginTransaction();
                commit = true;
            }
            ((PostDal)dal).Delete(_Id, concurencyId);
            if (commit)
            {
                Change tmp = new Change() { Action = Change.Actions.Deleted, UserId = 0, Created = DateTime.Now, Key = Id.ToString(), Type = Change.ChangeTypes.Post, Description = string.Concat(this.DisplayName, " - ", this.Path)};
                CommitTransaction();
            }
        }

        private List<PostControl> controls;
        public virtual List<PostControl> Controls
        {
            get
            {
                if (controls == null && this.Id > 0)
                {
                    controls = Bll.PostControl.GetAllByPostId(Id);
                }
                return controls;
            }
        }

        public virtual PostControl FindPostControl(string name)
        {
            if (Controls != null)
            {
                foreach (PostControl ctrl in Controls)
                {
                    if (ctrl.Name == name)
                    {
                        return ctrl;
                    }
                }
            }
            return null;
        }

        private List<Post> children;
        public virtual List<Post> Children
        {
            get
            {
                if (children == null)
                {
                    children = GetChildren(SiteVersion);
                }
                return children;
            }
        }

        public List<Post> GetChildren(DateTime? siteVersion)
        {
            return GetAllByParentGuid(SiteId, this.PostGuid, siteVersion);
        }

        public Post FindChildByName(string name)
        {
            if (string.IsNullOrEmpty(name))
                return null;
            foreach (Post p in Children)
            {
                if (p.Name.ToLower() == name.ToLower())
                    return p;
            }
            return null;
        }


        private List<Topic> topics;
        public List<Topic> GetTopics()
        {
            if (topics == null)
            {
                topics = Topic.GetAllByPostId(this.Id);
            }
            return topics;
        }

        public Topic GetFirstTopic()
        {
            List<Topic> tmp = GetTopics();
            if (tmp != null && tmp.Count > 0)
            {
                return tmp[0];
            }
            else
            {
                return null;
            }
        }

        private TemplateFile defaultFile;
        public TemplateFile GetDefaultFile()
        {
            if (defaultFile == null)
            {
                defaultFile = TemplateFile.GetDefault(this.TemplateId);
            }
            return defaultFile;
        }

        private Dictionary<string, TemplateFile> files;
        public TemplateFile GetFile(string name)
        {
            if (files == null)
            {
                files = new Dictionary<string, TemplateFile>();
            }
            if (!files.ContainsKey(name))
            {
                files.Add(name, TemplateFile.GetByTemplateIdAndName(this.TemplateId, name));
            }
            return files[name];
        }

        public string GetDefaultQueryString()
        {
            return GetQueryString(GetDefaultFile());
        }

        public string GetQueryString(string name)
        {
            return GetQueryString(GetFile(name));
        }

        public string GetQueryString(TemplateFile file)
        {
            if (file != null)
            {
                System.Text.StringBuilder queryString = new StringBuilder();
                queryString.AppendFormat("AcmsPostId={0}", Id);
                queryString.AppendFormat("&AcmsSiteId={0}", SiteId);
                if (!string.IsNullOrEmpty(file.MasterPagePath))
                    queryString.AppendFormat("&AcmsMasterPagePath={0}", file.MasterPagePath);
                if (!string.IsNullOrEmpty(file.Path))
                    queryString.AppendFormat("&AcmsTemplatePath={0}", file.Path);
                if (!string.IsNullOrEmpty(file.Theme))
                    queryString.AppendFormat("&AcmsTheme={0}", file.Theme);
                return queryString.ToString();
            }
            else
            {
                return null;
            }
        }

        public void Publish()
        {
            Publish(false, false);

        }

        public void Publish(bool includeChidren, bool includeOnlyMarked)
        {
            Publish(includeChidren, includeOnlyMarked, DateTime.Now, null);
        }

        private void AddChildrenToPublish(List<Post> postsToPublish, bool includeOnlyMarked, Post parent)
        {
            List<Post> children = parent.GetChildren(null);
            foreach (Post p in children)
            {
                if (p.RequiresPublishing)
                {
                    if (p.ReadyToPublish || !includeOnlyMarked)
                    {
                        postsToPublish.Add(p);
                    }
                }
            }

            foreach (Post p in children)
            {
                AddChildrenToPublish(postsToPublish, includeOnlyMarked, p);
            }
        }

        public void Publish(bool includeChidren, bool includeOnlyMarked, DateTime from, DateTime? to)
        {
            var dal = (PostDal)CreateDal();
            var data = dal.Publish(this.Id, includeChidren, includeOnlyMarked, from, to);
            Load(data);
            /*List<Post> postsToPublish = new List<Post>();
            postsToPublish.Add(this);

            if (includeChidren)
            {
                AddChildrenToPublish(postsToPublish, includeOnlyMarked, this);
            }

            if (postsToPublish.Count > 0)
            {
                //begin tran
                bool commitTran = false;
                if (this.TransactionKey != Guid.Empty)
                {
                    if (postsToPublish[0].TransactionKey == Guid.Empty)
                    {
                        postsToPublish[0].UseTransaction(this.TransactionKey);
                    }
                }
                else
                {
                    postsToPublish[0].BeginTransaction();
                    commitTran = true;
                }

                try
                {
                    foreach (Post tmpPost in postsToPublish)
                    {
                        if (tmpPost.TransactionKey != postsToPublish[0].TransactionKey)
                        {
                            tmpPost.UseTransaction(postsToPublish[0].TransactionKey);
                        }
                        tmpPost.PublishFrom = from;
                        tmpPost.PublishTo = to;
                        tmpPost.RequiresPublishing = false;
                        tmpPost.Update();
                    }
                    var dal = (PostDal)CreateDal();
                    dal.UseTransaction(postsToPublish[0].TransactionKey);
                }
                catch
                {
                    if (commitTran)
                    {
                        postsToPublish[0].RollbackTransaction();
                    }
                    throw;
                }

                if (commitTran)
                {
                    postsToPublish[0].CommitTransaction();
                }
            }*/

        }


        public static void RemoveDuplicates(List<Post> posts)
        {
            List<int> ids = new List<int>();
            foreach (Post p in posts)
            {
                if (ids.Contains(p.Id))
                {
                    posts.Remove(p);
                }
                else
                {
                    ids.Add(p.Id);
                }
            }
        }

        public void Retire()
        {
            if (this.PublishFrom <= DateTime.Now)
            {
                this.PublishTo = DateTime.Now;
                this.Update();
            }
            else
            {
                throw new ApplicationException("You can only reire posts that have been live. Otherwise you should delete them.");
            }
        }
        /*public void Retire(bool allVersions)
        {
            List<Post> postToRetire = new List<Post>();
            if (this.PublishTo == null || this.PublishTo.Value > DateTime.Now)
            {
                postToRetire.Add(this);
            }
            if (allVersions)
            {
                foreach (Post tmp in Post.GetCurrentVersions(this.PostGuid))
                {
                    if (tmp.Id != this.Id)
                    {
                        postToRetire.Add(tmp);
                    }
                }
            }
            if (postToRetire.Count > 0)
            {
                postToRetire[0].BeginTransaction();
                foreach (Post p in postToRetire)
                {
                    if (p.TransactionKey == Guid.Empty)
                    {
                        p.UseTransaction(postToRetire[0].TransactionKey);
                    }
                    p.PublishTo = DateTime.Now;
                    p.Update();
                }
                postToRetire[0].CommitTransaction();
            }
        }*/

        private class PostCopyDetails
        {
            public Post Post { get; set; }
            public Post Copy { get; set; }
            public Guid ParentGuid { get; set; }
            public List<PostTopic> Topics { get; set; }
            public List<PostControl> Controls { get; set; }
            public List<PostMenu> Menus { get; set; }
            public List<PostCopyDetails> Children;
        }

        private static void RecursiveAddPostsToCopy(Post post, List<PostCopyDetails> posts)
        {
            foreach (Post child in post.Children)
            {
                PostCopyDetails tmp = new PostCopyDetails();
                tmp.Post = child;
                tmp.Topics = PostTopic.GetAllByPostId(child.Id);
                tmp.Controls = PostControl.GetAllByPostId(child.Id);
                tmp.Menus = PostMenu.GetAllByPostId(child.Id);
                tmp.Children = new List<PostCopyDetails>();

                posts.Add(tmp);
                RecursiveAddPostsToCopy(child, tmp.Children);
            }
        }

        private static void RecursiveCopyPost(PostCopyDetails postToCopy, Guid? transactionKey)
        {
            bool comitTran = false;

            Post copy = Post.CreateInstance();
            if (!transactionKey.HasValue)
            {
                comitTran = true;
                copy.BeginTransaction();
                copy.Name = string.Concat("Copy_", postToCopy.Post.Name);
                copy.DisplayName = string.Concat("Copy Of ", postToCopy.Post.DisplayName);
            }
            else
            {
                copy.UseTransaction(transactionKey.Value);
                copy.Name = postToCopy.Post.Name;
                copy.DisplayName = postToCopy.Post.DisplayName;
            }
            copy.ParentGuid = postToCopy.ParentGuid;
            copy.Notes = postToCopy.Post.Notes;
            copy.SiteId = postToCopy.Post.SiteId;
            copy.Summary = postToCopy.Post.Summary;
            copy.TemplateId = postToCopy.Post.TemplateId;
            copy.ThumbnailId = postToCopy.Post.ThumbnailId;

            copy.Update();

            postToCopy.Copy = copy;

            foreach (PostControl ctrl in postToCopy.Controls)
            {
                PostControl copyControl = PostControl.CreateInstance(copy.Id, ctrl.TemplateControlId, ctrl.Value);
                copyControl.UseTransaction(copy.TransactionKey);
                copyControl.Update();
            }

            foreach (PostMenu menu in postToCopy.Menus)
            {
                PostMenu copyMenu = PostMenu.CreateInstance(copy.Id, menu.MenuId, menu.Included);
                copyMenu.UseTransaction(copy.TransactionKey);
                copyMenu.Update();
            }

            foreach (PostTopic topic in postToCopy.Topics)
            {
                PostTopic copyTopic = PostTopic.CreateInstance(copy.Id, topic.TopicId);
                copyTopic.UseTransaction(copy.TransactionKey);
                copyTopic.Update();
            }

            foreach (PostCopyDetails p in postToCopy.Children)
            {
                p.ParentGuid = copy.PostGuid;
                RecursiveCopyPost(p, copy.TransactionKey);
            }
            if (comitTran)
            {
                copy.CommitTransaction();
            }
        }

        public static Post Copy(Post post, bool includeChildren)
        {

            PostCopyDetails postsToCopy = new PostCopyDetails();
            postsToCopy.Post = post;
            postsToCopy.Topics = PostTopic.GetAllByPostId(post.Id);
            postsToCopy.Controls = PostControl.GetAllByPostId(post.Id);
            postsToCopy.Menus = PostMenu.GetAllByPostId(post.Id);
            postsToCopy.ParentGuid = post.ParentGuid.Value;
            postsToCopy.Children = new List<PostCopyDetails>();
            
            RecursiveAddPostsToCopy(post, postsToCopy.Children);
            Guid? transactionKey = null;
            RecursiveCopyPost(postsToCopy, transactionKey);
            return postsToCopy.Copy;
        }


        public void SetPosition(Guid newParentGuid, int newSequence)
        {
            if (newParentGuid != this.ParentGuid || newSequence != this.Sequence)
            {
                var dal = (PostDal)CreateDal();
                //holders for refs
                var sequence = newSequence;
                var concurencyID = base.ConcurencyId;

                dal.SetPosition(this.Id, this.SiteId, newParentGuid, ref sequence, ref concurencyID);

                //set properties
                this.ParentGuid = newParentGuid;
                this.Sequence = sequence;
                this.SetVersionId(concurencyID);
            }
        }

        public string TitleSummary { get; set; }
        public string MetaKeywords { get; set; }
    }
}
